//
// Created by mayunxi on 2020/6/8.
//

#ifndef FFMPEG_GPU_DECODER_H
#define FFMPEG_GPU_DECODER_H
#include <string>
#include <time.h>
#include <list>
#include <Windows.h>
using namespace std;
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/pixdesc.h"
#include "libavutil/opt.h"
#include "libavutil/avassert.h"
#include "libavutil/imgutils.h"
#include "libavutil/pixfmt.h"
#include "libavutil/hwcontext_qsv.h"
#include "libswscale/swscale.h"

#include "SDL2/SDL.h"
}

#include <map>
#include <iostream>

#if USE_LOG4PLUS

#else
extern int g_logger;
extern void LOG4CPLUS_ERROR(int log, string msg);
extern void LOG4CPLUS_WARN(int log, string msg);
#endif

#define SLEEP_US 1000

typedef struct CHANNEL_INFO_SET{
    bool rtsp_url_ok = false;
    string rtsp_url;
    map<int,int> fd_map;
    int first_fd = -1;
    int status=0;

    float scale = 1;
    int fps = 10;
    string dec_type= "";
    string pic_format;

};
typedef struct {
    char _url[256];
    string ip;
    char host[64];
    int port = 554; //default port=554
    char usr[64];
    char passwd[64];
    char realm[64];
    char nonce[64];
    int rtspSocket = -1;
    char control[256];
}RTSP_INFO;
typedef struct {
    time_t lasttime;
} Runner;
class PACKET_INFO
{
public:

    bool m_push_flag = false;
    string m_position = "";
    string m_frame_num="";
    unsigned char m_delay_cnt = 0;
};
class Decoder {
public:
    explicit Decoder(CHANNEL_INFO_SET channel_info);
    virtual ~Decoder();
    void FreeResource();

public:
    virtual bool init() = 0;
    virtual int GetPicture() = 0;

    bool ParseRtsp(void);
    static void GlobalInit();

    int GetVideoWidth(){ return m_video_width;}
    int GetVideoHeight(){ return m_video_height;}
    int GetVideoFps(){ return m_fps;}


public:

    RTSP_INFO m_rtsp_info;
    //AVFormatContext - 描述了媒体文件的构成及基本信息，是统领全局的基本结构体，贯穿程序始终，很多函数都要用它作为参数；
    AVFormatContext *m_input_avfmt_ctx = NULL;
    AVDictionary *m_opts=NULL;
    //AVCodecContext - 描述编解码器上下文的数据结构，包含了众多编解码器需要的参数信息；
    AVCodecContext *m_decoder_ctx = NULL;
    ///AVCodec - 编解码器对象，每种编解码格式(例如H.264、AAC等）对应一个该结构体，
    /// 如libavcodec/aacdec.c的ff_aac_decoder。每个AVCodecContext中含有一个AVCodec；
    AVCodec *m_avcodec = NULL;
    //AVPacket - 存放编码后、解码前的压缩数据，即ES数据；

    //AVFrame - 存放编码前、解码后的原始数据，如YUV格式的视频数据或PCM格式的音频数据等；
    AVFrame *m_avframe = NULL;

    Runner m_input_runner = {0};
    //输出流相关
    AVFormatContext * m_out_fmt_ctx = NULL;
    string m_out_url="";
    bool m_out_ok= false;
    int m_push_failed_cnt = 0;

    //编码相关
    AVCodecContext *m_enc_ctx=NULL;
    AVCodec *m_pCodec = NULL;

    int m_video_stream_index=-1;
    unsigned short m_frame_num=0;//帧数
    int m_pic_num = 0;
    string m_pic_path="";
    string m_pic_name = "";
    int m_out_width = 0;
    int m_out_height = 0;
    int m_video_width = 0;
    int m_video_height = 0;
    int m_fps = 10;

    uint8_t m_frame_num_1s = 1;

public:
    //设置相关
    CHANNEL_INFO_SET m_channel_set;
    int m_channel_num;
    bool m_init_ok=0;
    int m_interval=1;

    string m_err_code;
    string m_msg;

    //for monitor
    bool m_flag;

    int m_cnt=0;
    list<float> m_use_time_list;
    int m_skip_frame_num=0;
    //for computing fps

    list<float> m_fps_time_list;
    int m_fps_skip_num=0;

    SwsContext* m_img_convert_ctx = NULL;
    AVFrame* m_pFrameYUV = NULL;
    unsigned char* m_out_buffer = NULL;
   
};
extern  int interrupt_callback(void *p);

#define DEFAULT_MODE ""
#define KEY_FRAME "1"
#define ONLY_PUSH "2"
#define DEC_AND_PUSH "3"


#define PRINTF_BUFFER_SIZE 1024
extern char g_ffmpeg_err[PRINTF_BUFFER_SIZE];

//Refresh Event
#define SFM_REFRESH_EVENT  (SDL_USEREVENT + 1)

#define SFM_BREAK_EVENT  (SDL_USEREVENT + 2)
extern int m_thread_exit;
extern int m_thread_pause;
extern bool DisplayInit(int width, int height);
extern void Display(AVFrame* frame );
extern SDL_Renderer* m_sdlRenderer;
extern SDL_Texture* m_sdlTexture;
extern SDL_Event m_event;

#endif //FFMPEG_GPU_DECODER_H
